package kpanelhandler;

import java.awt.BorderLayout;
import java.awt.LayoutManager;
import java.util.Hashtable;
import javax.swing.JPanel;

/**
 * This class provide a way to manage multiples panels. A KPanelHandler have a
 * collection of panels of the class <b>{@link KPanel}</b>, and provide
 * operations to change between them. Only one panel will be the current one at
 * a time. Each panel in the collection, has a unique key that identify it from
 * the rest.
 * <p>
 * The methods <b>{@link #changeTo(String, String, Object[])}</b> and <b>
 * {@link #changeTo(String)}</b> are used to change to an specific panel in the
 * collection using the unique key. Check out the operation documentation.
 * 
 * <p>
 * Last version: February 2, 2013
 * <p>
 * 
 * @author Matias Varela
 *         <p>
 *         Student of Licenciatura en Ciencias de la Computacion, at the
 *         Universidad Nacional del Sur (Argentina).
 *         <p>
 *         project site: http://code.google.com/p/kpanelhandler-project/
 * 
 * 
 * 
 */
@SuppressWarnings("serial")
public class KPanelHandler extends JPanel {

	// collection of panels.
	protected Hashtable<String, KPanel> panels;

	// key of the current panel.
	public String current_panel;

	/**
	 * Constructs a
	 */

	/**
	 * Constructs a new KPanelHandler. By default, the current panel will be a
	 * new panel of the class {@link KPanel} which is associated with the key
	 * "DEFAULT".
	 */
	public KPanelHandler() {
		this.panels = new Hashtable<String, KPanel>();
		super.setLayout(new BorderLayout(0, 0));
		this.addPanel(new KPanel("DEFAULT"));
		this.current_panel = "DEFAULT";
		this.add(panels.get("DEFAULT"));
	}

	/**
	 * Constructs a new KPanelHandler. The default panel is passed by argument
	 * and it is set to be the current panel.
	 * 
	 * @param defaultPanel
	 *            The panel that will be the default panel.
	 */
	public KPanelHandler(KPanel defaultPanel) {
		this.panels = new Hashtable<String, KPanel>();
		super.setLayout(new BorderLayout(0, 0));
		this.addPanel(defaultPanel);
		this.add(defaultPanel);
	}

	/**
	 * Performs a change to the <b>panel</b> associated with
	 * <code>key_target_panel</code> (which is called <b>target panel</b>) and
	 * execute the action command associated with <code>key_command</code>
	 * defined in the <b>target panel</b>. The <b>target panel</b> will be set
	 * as the current panel of this KPanelHandler.
	 * <p>
	 * The operation has success if the <code>key_target_panel</code> and
	 * <code>key_command</code> are valid.
	 * 
	 * 
	 * @param key_target_panel
	 *            key of the target panel.
	 * @param key_command
	 *            key of the action command defined in the target panel.
	 * @param params
	 *            parameters that will be used by the action command.
	 * @return whether the operation has succeeded: <code>true</code> if the
	 *         operation has succeeded;<code>false</code> otherwise.
	 */
	public boolean changeTo(String key_target_panel, String key_command,
			Object[] params) {
		// if key_target_panel exists.
		if (panels.containsKey(key_target_panel)) {
			// get the new KPanel associated with key_target_panel.
			KPanel newPanel = this.panels.get(key_target_panel);

			// if the action command exists.
			if (newPanel.containsActionCommand(key_command)) {
				// save the old panel key.
				String old_panel = this.current_panel;

				// set the new current panel key.
				this.current_panel = key_target_panel;

				// execute the action command.
				KActionCommand action_command = newPanel
						.getActionCommand(key_command);
				action_command.doAction(old_panel, params);

				// show the new panel.
				this.removeAll();
				this.add(newPanel);

				// do the transition effect associated
				// if (newPanel.hasEffect()) newPanel.startEffect();

				// paint everything
				if (this.getParent() != null)
					this.getParent().paintAll(this.getParent().getGraphics());

				return true;
			} else
				return false;
		} else
			return false;
	}

	/**
	 * Performs a change to the <b>panel</b> associated with
	 * <code>key_target_panel</code> (which is called <b>target panel</b>). The
	 * <b>target panel</b> will be set as the current panel of this
	 * KPanelHandler.
	 * <p>
	 * The operation has success if the <code>key_target_panel</code> is valid.
	 * 
	 * @param key_panel
	 *            key of the target panel.
	 * @return whether the operation has succeeded: <code>true</code> if the
	 *         operation has succeeded;<code>false</code> otherwise.
	 */
	public boolean changeTo(String key_panel) {
		// if the key_panel exists.
		if (panels.containsKey(key_panel)) {
			// the new panel is the current one.
			this.current_panel = key_panel;
			// get the new panel.
			KPanel newPanel = this.panels.get(key_panel);

			// add the new panel to this container.
			this.removeAll();
			this.add(newPanel);

			// if (newPanel.hasEffect()) newPanel.startEffect();

			// paint everything
			if (this.getParent() != null)
				this.getParent().paintAll(this.getParent().getGraphics());

			return true;
		} else
			return false;
	}

	/**
	 * Execute an action of the panel associated with <b>key_panel</b>. The
	 * action to be executed has the key <b>key_command</b>. Both
	 * <b>key_panel</b> and <b>key_command</b> must be valid.
	 * 
	 * @param key_panel
	 *            key of the panel
	 * @param key_command
	 *            key of an action command of the panel
	 * @param params
	 *            parameters that will be used by the action command.
	 * @return true if the action could be executed. False otherwise.
	 */
	public boolean executeActionCommand(String key_panel,
			String key_command, Object[] params) {
		// if the key_panel exists.
		if (panels.containsKey(key_panel)
				&& panels.get(key_panel).containsActionCommand(
						key_command)) {
			this.panels.get(key_panel).getActionCommand(key_command)
					.doAction(getCurrentKeyPanel(), params);
			return true;
		}
		return false;
	}

	/**
	 * Add a new panel to the collection. Note that if the key of the
	 * <code>new_panel</code> has already been defined in the collection of this
	 * <b>KPanelHandler</b>, then it will replace the old one. (The keys must be
	 * unique).
	 * 
	 * @param new_panel
	 *            The new panel to be added to the collection.
	 */
	public void addPanel(KPanel new_panel) {
		this.panels.put(new_panel.getKey(), new_panel);
		new_panel.setHandler(this);
	}

	/**
	 * Remove a panel associated with <code>key</code> from the collection of
	 * this class.
	 * 
	 * @param key
	 *            The key associated with the panel that will be removed.
	 * @return whether the panel has been removed successfully. Returns
	 *         <code>true</code> if <code>key</code> exists in the collection;
	 *         <code>false</code> otherwise.
	 */
	public boolean removePanel(String key) {
		if (this.panels.contains(key)) {
			this.panels.remove(key);
			return true;
		} else
			return false;
	}

	/**
	 * Returns the current panel.
	 * 
	 * @return The current panel.
	 */
	public KPanel getCurrentPanel() {
		return this.panels.get(this.current_panel);
	}

	/**
	 * Returns the key associated with the current panel.
	 * 
	 * @return The key associated with the current panel.
	 */
	public String getCurrentKeyPanel() {
		return current_panel;
	}

	/**
	 * Returns the panel associated with <code>key</code>.
	 * 
	 * @param key
	 *            unique key of the panel to be gotten.
	 * @return A <code>KPanel</code> Object associated with <code>key</code>
	 *         passed by argument; Returns a <code>null</code> Object if
	 *         <code>key</code> does not exist in the collection.
	 */
	public KPanel getKPanel(String key) {
		if (panels.containsKey(key))
			return panels.get(key);
		else
			return null;
	}

	@Override
	public final void setLayout(LayoutManager mgr) {
		// nothing here.
	}

}
